var fs = require('fs');
var path = require('path');
var through = require('through2');
var gutil = require('gulp-util');
var cheerio = require('cheerio');
var sass = require('node-sass');
var beautify = require('js-beautify').html;
var babel = require("babel-core");
var PluginError = gutil.PluginError;

// 常量
const PLUGIN_NAME = 'gulp-trim-js-css';

// 插件级别的函数（处理文件）
function publicFun(options) {
  // 创建一个 stream 通道，以让每个文件通过
  var stream = through.obj(function (file, enc, cb) {
    if (file.isStream()) {
      this.emit('error', new PluginError(PLUGIN_NAME, 'Streams are not supported!'));
      return cb();
    }

    if (file.isBuffer()) {
      try{
        file = trimJsCss(file);
      }catch (error){
        console.error(PLUGIN_NAME,':', error.message.toString());
        return cb();
      }
    }

    // 确保文件进入下一个 gulp 插件
    this.push(file);

    // 告诉 stream 引擎，我们已经处理完了这个文件
    cb();
  });

  // 返回文件 stream
  return stream;
};

//整理js、css
function trimJsCss(file) {
  file = trimLink(file)
  file = trimCss(file)
  file = trimJs(file)

  var content = file.contents.toString();
  content = beautify(content,{ indent_size: 2 });

  file.contents = new Buffer(content);
  return file;
}

//处理css
function trimCss(file) {
  //文件内容
  var content = file.contents.toString();

  //查找style标签的正则表达式
  var reg = /<!--[\s\S]*?-->|<style[\s\S]*?<\/style>\s*/g;
  //查找style标签
  var styleTags = content.match(reg);

  var allCss = ''

  for(var i in styleTags){

    //跳过注释
    if (/^<!--/.test(styleTags[i])) {
      continue
    }

    content = content.replace(styleTags[i],'')

    var cssText = styleTags[i].replace(/^<.+?>|<.+?>\s*$/g,'')
    if(cssText.replace(/\s/g,'')){
      try{
        var result = sass.renderSync({
          data: cssText,
          outputStyle: 'compact'
        })
        allCss += result.css.toString().replace('@charset "UTF-8";','')
      }catch (error){
        console.error(PLUGIN_NAME,':', error.message.toString());
      }
    }
  }

  if(allCss.replace(/\s/g,"").length){
    allCss = '<style>\n'+allCss+'\n</style>\n</head>';
    content = content.replace('</head>',allCss);
    //返回替换后的file
    file.contents = new Buffer(content);
  }

  return file;
}

//处理js
function trimJs(file) {
  //文件内容
  var content = file.contents.toString()

  //查找script标签的正则表达式
  var reg = /<!--[\s\S]*?-->|<script[\s\S]*?<\/script>\s*/g;
  //查找script标签
  var scriptTags = content.match(reg)

  var allJs = ''
  var allFile = []

  for(var i in scriptTags){
    //跳过注释
    if (/^<!--/.test(scriptTags[i])) {
      continue
    }

    if (/<script[^>]*type[^>]*template[^>]*>/.test(scriptTags[i])) {
      continue
    }

    //删除原script标签
    content = content.replace(scriptTags[i],'')

    if(/^<script.*?(src=).*?>/.test(scriptTags[i])){
      allFile.push(scriptTags[i])
      continue;
    }

    var jsText = scriptTags[i].replace(/^<.+?>|<.+?>\s*$/g,'')

    if(jsText.replace(/\s/g,'')){
      try{
        var result = babel.transform(jsText,{presets: ['es2015']})
        allJs += result.code
      }catch (error){
        console.error(PLUGIN_NAME,':', error.message.toString())
      }
    }
  }

  var addCode = ''
  for(var i=0;i<allFile.length;i++){
    addCode += allFile[i]
  }

  allJs = allJs.replace(/['"]use strict['"];/g,'')
  if(allJs.replace(/\s/g,"").length){
    addCode += '<script>\n'+allJs+'\n</script>\n</body>'
  }else{
    addCode += '\n</body>'
  }

  content = content.replace('</body>',addCode)

  //返回替换后的file
  file.contents = new Buffer(content)
  return file;
}

//处理link
function trimLink(file) {
  //文件内容
  var content = file.contents.toString()

  //查找link标签的正则表达式
  var reg = /<!--[\s\S]*?-->|<link.*?>\s*/g;
  //查找script标签
  var tags = content.match(reg)

  var allFile = []

  for(var i in tags){
    //跳过注释
    if (/^<!--/.test(tags[i])) {
      continue
    }

    //删除原script标签
    content = content.replace(tags[i],'')

    allFile.push(tags[i])

  }

  var addCode = ''
  for(var i=0;i<allFile.length;i++){
    addCode += allFile[i]
  }

  addCode += '\n</head>'

  content = content.replace('</head>',addCode)

  //返回替换后的file
  file.contents = new Buffer(content)
  return file;
}

// 导出插件主函数
module.exports = publicFun;